package com.spa.application.service.admin;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.spa.application.command.admin.MenuAddCommand;
import com.spa.application.command.admin.ResourceAddCommand;
import com.spa.application.command.admin.ResourceEditCommand;
import com.spa.application.dto.PageResult;
import com.spa.application.dto.admin.ResourceDTO;
import com.spa.application.dto.admin.menu.geeker.MenuDTO;
import com.spa.application.dto.admin.menu.geeker.MenuSelectDTO;
import com.spa.application.query.admin.ResourceQuery;
import com.spa.domain.entity.Menu;
import com.spa.domain.entity.Resource;
import com.spa.domain.entity.SysUserEntity;
import com.spa.domain.service.MenuService;
import com.spa.domain.service.ResourceService;
import com.spa.domain.service.SysAdminUserService;
import com.spa.infrastructure.mapper.MenuMapStruct;
import com.spa.infrastructure.repository.po.MenuPO;
import com.spa.infrastructure.util.SessionUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.stream.Collectors;

/**
 * 资源服务.
 *
 * @author liangjun
 */
@Service
public class ResourceApplicationService {

    @Autowired
    private ResourceService resourceService;

    @Autowired
    private MenuAssembler menuAssembler;

    @javax.annotation.Resource
    private MenuService menuService;

    @Autowired
    private ObjectMapper mapper;

    @javax.annotation.Resource
    private SysAdminUserService sysUserService;

    /**
     * 获取所有的资源.
     *
     * @return 资源列表
     */
    public List<ResourceDTO> list() {
        return menuAssembler.resourceDTOList(resourceService.list(new ResourceQuery()));
    }

    /**
     * 获取当前用户拥有的资源.
     *
     * @return 资源列表
     */
    public List<ResourceDTO> listResourceByUser() {
        Long userId = SessionUtil.getUser().getExtUserId();
        ResourceQuery resourceQuery = new ResourceQuery();
        return menuAssembler.resourceDTOList(resourceService.list(resourceQuery));
    }

    /**
     * 分页获取所有的资源.
     *
     * @return 资源列表
     */
    public PageResult<ResourceDTO> page(ResourceQuery query) {
        Page<Resource> resourcePage = resourceService.page(query);
        List<ResourceDTO> resourceDTOList = menuAssembler.resourceDTOList(resourcePage.getRecords());
        PageResult<ResourceDTO> resourceDTOPage = new PageResult<>();
        resourceDTOPage.setCurrent(resourcePage.getCurrent());
        resourceDTOPage.setTotal(resourcePage.getTotal());
        resourceDTOPage.setSize(resourcePage.getSize());
        resourceDTOPage.setRecords(resourceDTOList);
        return resourceDTOPage;
    }

    /**
     * 新增一个资源.
     *
     */
    public void add(ResourceAddCommand command) {
        resourceService.add(command);
    }

    /**
     * 修改一个资源.
     *
     */
    public void edit(ResourceEditCommand command) {
        resourceService.edit(command);
    }

    /**
     * 删除一个资源.
     *
     */
    public boolean delById(Long id) {
        return resourceService.delById(id);
    }
    /**
     * 启用/禁用.
     *
     */
    public boolean enableDisabled(Long id) {
        return resourceService.enableDisabled(id);
    }

    public void addMenu(MenuAddCommand command) {
        MenuPO po = MenuMapStruct.INSTANCE.addCommand2Po(command);
        MenuDTO.Meta meta = new MenuDTO.Meta();
        meta.setActiveMenu(command.getActiveMenu());
        meta.setFull(command.isFull());
        meta.setIcon(command.getIcon());
        meta.setHide(command.isHide());
        meta.setAffix(command.isAffix());
        meta.setTitle(command.getTitle());
        meta.setIsLink(command.getIsLink());
        meta.setKeepAlive(command.isKeepAlive());
        try {
            po.setMeta(mapper.writeValueAsString(meta));
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
        menuService.addMenu(po);
    }

    public List<MenuDTO> menuList() {
        long userId = SessionUtil.getUser().getExtUserId();
        SysUserEntity userEntity = sysUserService.infoById(userId);
        if (isAdmin(userEntity.getRoleId())) {
            return assembler(menuService.getAllMenus());
        }
        return assembler(menuService.getMenusByIds(userEntity.getRoleId()));
    }

    private boolean isAdmin(long roleId) {
        return roleId == 1 || roleId == 1773596698399678465L;
    }
    public List<MenuSelectDTO> menuList4Select() {
        List<MenuDTO> menuDTOList = assembler(menuService.getAllMenus());
        return MenuMapStruct.INSTANCE.dto2dtoList(menuDTOList);
    }

    private List<MenuDTO> assembler(List<Menu> menuList) {
        List<MenuDTO> menuDTOList = MenuMapStruct.INSTANCE.entity2MenuDTO4List(menuList);
        List<MenuDTO> topList = menuDTOList.stream()
                .filter(menuDTO -> menuDTO.getPid() == 0)
                .collect(Collectors.toList());
        menuDTOList.removeAll(topList);
        fill(topList, menuDTOList);
        return topList;
    }

    private void fill(List<MenuDTO> parentList, List<MenuDTO> unprocessedList) {
        parentList.stream()
                .map(parent -> fillChild(parent, unprocessedList))
                .filter(childList -> !childList.isEmpty())
                .forEach(childList -> {
                    unprocessedList.removeAll(childList);
                    fill(childList, unprocessedList);
                });
    }

    private List<MenuDTO> fillChild(MenuDTO parent, List<MenuDTO> unprocessedList) {
        List<MenuDTO> child = unprocessedList.stream()
                .filter(unprocessed -> ObjectUtil.equals(unprocessed.getPid(), parent.getId()))
                .collect(Collectors.toList());
        parent.setChildren(child);
        return child;
    }

}
